#include <cmath>
#include <iostream>
#include <QtScript>

#include "qanimal.h"
#include "dna.h"

QAnimal::QAnimal ( QGame* parent, Dna* dna, int n, int width, int height ) : QLife ( parent, dna, n, width, height )
{
	name = "QAnimal";

	fighting = false;
	viewDistance = dna -> getViewDistance();

	game = parent;

	gravity = NULL;
	enemy = NULL;

	x = rand() % getWidth();
	y = rand() % getHeight();

	xDest = rand() % getWidth();
	yDest = rand() % getHeight();

	maxSpeed = dna -> getMaxSpeed();
	speed = maxSpeed / 2;
}

QAnimal::~QAnimal()
{}

bool QAnimal::isFighting()
{
	return fighting;
}

float QAnimal::getXDest()
{
	return xDest;
}

float QAnimal::getYDest()
{
	return yDest;
}

float QAnimal::getViewDistance()
{
	return viewDistance;
}

void QAnimal::attack ( QAnimal* source, float attackStrength )
{
	fighting = true;
	gravity = NULL;
	enemy = source;

	energy = energy - attackStrength;
}

int QAnimal::getFactor ( float d, float p )
{
	if ( ( d - p ) > 2 )
	{
		return -1;
	}
	else if ( ( d - p ) < 2 )
	{
		return 1;
	}
	else
	{
		return 0;
	}
}

QAnimal* QAnimal::getEnemy()
{
	return enemy;
}

void QAnimal::think()
{
	QScriptEngine engine;
	QScriptValue thisVal = engine.newQObject(this);
	engine.globalObject().setProperty("animal", thisVal);
	
	if ( !alive )
	{
		decay();
		return;
	}

/*	QFile file("animal.js");
    file.open(QIODevice::ReadOnly);
    engine.evaluate(file.readAll());
	if (engine.hasUncaughtException()) {
		std::cerr << "[WARNING]\tException in script on line " << engine.uncaughtExceptionLineNumber() << ".\n";
		QStringList backTrace = engine.uncaughtExceptionBacktrace();
		for (int i = 0; i < backTrace.size(); ++i) {
			std::cerr << "\t" << backTrace.at(i).toLocal8Bit().constData() << "\n";
		}
		alive = false;
	}*/

	// search next gravity if not fighting
	if ( !fighting )
	{
		gravity = game -> getNextGravity ( this );
		// search enemy otherwise
		if ( gravity == NULL )
		{
			enemy = game -> getNextAnimal ( this );
		}
	}

	// set destination
	if ( enemy != NULL )
	{
		xDest = enemy -> getX();
		yDest = enemy -> getY();

		speed = maxSpeed;
	}
	else if ( gravity != NULL )
	{
		xDest = gravity -> getX();
		yDest = gravity -> getY();

		speed = maxSpeed;
	}
	else
	{
		float waitProb = ((dna -> getWaitWillingness()) / energy);
		if (waitProb >= 1) speed = 0;
		else speed = maxSpeed / 2;
	}

	// calculate distance to current destination
	float d = sqrt ( pow ( x - xDest, 2 ) + pow ( y - yDest, 2 ) );

	// close enough - do something
	if ( d < 20 )
	{
		// don't eat if you are full
		if ( gravity != NULL )
		{
			// don't eat if you are full
			if ( ! ( energy >= 150 ) )
			{
				float food = gravity -> eat();
				energy += food;
				if ( food == 0 ) gravity = NULL;
			}
		}
		else if ( enemy != NULL )
		{
			if ( enemy -> isAlive() )
			{
				fighting = true;
				enemy -> attack ( this, dna -> getAttackStrength() );
			}
			else
			{
				fighting = false;

				// don't eat if you are full
				if ( ! ( energy >= 150 ) )
				{
					float food = enemy -> eat();
					energy += food;
					if ( food == 0 ) enemy = NULL;
				}
			}
		}
		else
		{
			xDest = rand() % getWidth();
			yDest = rand() % getHeight();
		}
		// too far away - forget about it (only if destination is a life)
	}
	else if ( d > viewDistance && ( gravity != NULL || enemy != NULL ) )
	{
		if ( gravity != NULL ) gravity = NULL;
		if ( enemy != NULL ) enemy = NULL;
		// keep going
	}
	else
	{
		dx = ( rand() % 2 ) * speed;
		dy = ( rand() % 2 ) * speed;

		energy = energy - ( ( dx + dy ) / ( energy / 4 ) );

		x = x + dx * getFactor ( x, xDest );
		y = y + dy * getFactor ( y, yDest );
	}
}

void QAnimal::collectData()
{
	QStringList data;

	data << "Type" << "Animal";
	data << "Id" <<
	QString ( "%1" ).arg ( getId() );
	data << "" << "";
	data << "Energy" <<
	QString ( "%1 / 150" ).arg ( getEnergy(), 0, 'f', 1 );
	data << "Age" <<
	QString ( "%1 / %2" ).arg ( getAge(), 0, 'f', 1 ).arg ( dna -> getMaxAge(), 0, 'f', 1 );
	data << "Current Speed" <<
	QString ( "%1 / %2" ).arg ( speed, 0, 'f', 1 ).arg ( dna -> getMaxSpeed(), 0, 'f', 1 );
	data << "" << "";
	data << "AttackStrength" <<
	QString ( "%1" ).arg ( dna -> getAttackStrength(), 0, 'f', 1 );
	data << "View Distance" <<
	QString ( "%1" ).arg ( dna -> getViewDistance(), 0, 'f', 1 );
	data << "Pregnance Duration" <<
	QString ( "%1" ).arg ( dna -> getPregnanceDuration() );
	data << "" << "";
	data << "Is Alive" <<
	QString ( "%1" ).arg ( isAlive() );
	data << "Is Pregnant / Ticks to Birth" <<
	QString ( "%1 / %2" ).arg ( isPregnant() ).arg ( getPregnanceDuration() );

	emit ( config ( getId(), data ) );
}

QString QAnimal::getName()
{
	return name;
}

void QAnimal::initDecay()
{
	energy = 30;
}

void QAnimal::decay()
{
	energy = energy - 0.1;
}

void QAnimal::run()
{
	setPriority ( QThread::LowestPriority );
	exec();
}
